<?php
/**
 * This file defines the {@see \BF\Validation\IntegerValidator} class.
 *
 * @author     Kado <ulfikado@gmail.com>
 * @category   Beluga PHP5.3+ Framework
 * @package    BF\Validation
 * @since      2015-01-31 00:29
 * @subpackage Validators
 * @version    0.1
 */

namespace BF\Validation
{

   /**
    * This class defines a validator that allows only valid integer values
    *
    * @property integer|NULL $MinLength     The minimal allowed length or NULL if no min length should be used (default=1)
    * @property integer|NULL $MaxLength     The max allowed length or NULL if no max should used (default=\PHP_INT_MAX)
    * @property boolean      $AllowUrls     Can the text contain URLs to be valid? (default=TRUE)
    * @property integer      $MaxUrlCount   The max. count of allowed unknown URLs inside the text to validate.
    *                                       The default value -1 means, no limit.
    * @property array        $HostWhiteList Defining Host names, allowed to be used uncounted in URLs and mailaddresses.
    * @property boolean      $AllowMailAddresses Can the text contain mail adresses to be valid? (default=TRUE)
    * @property boolean      $AllowNewLines Can the text contain some linebreaks to be valid (default=TRUE)
    * @property integer      $MaxLineCount  How many lines can be defined by the value to check, to be valid?
    *                                       (Default = -1 means no limit => 0 is equal to 1 cause 0 lines have no sense)
    * @property boolean      $AllowHtml     Can the value to check contains some HTML content? (default=TRUE)
    * @property \BF\Converter\IHtmlToX      $HtmlConverter If HTML is allowed here you can define the Converter
    * @property boolean      $CheckForSpam  Should the text be checked if it contains some spam? (default=FALSE)
    *                                       It checks for some buzzwords and also checks for some spam hidding spellings
    *                                       like: V-I-A-G-R-A or something else.
    * @property-read string  $Result        Contains the resulting text string, after the call of ::validate(…)
    * @since    v0.1
    * @uses     \BF\Validation\Validator    It extends from this class
    */
   class TextValidator extends Validator
   {

      # <editor-fold defaultstate="collapsed" desc=" - - >   P U B L I C   C O N S T R U C T O R   - - - - - - - - - - - - - - - - - -">

      /**
       * Inits a new instance.
       *
       * Usable options are:
       *
       * - <b>MinLength</b>         : The minimal allowed length or NULL if no min length should be used (default=1)
       * - <b>MaxLength</b>         : The max allowed length or NULL if no max length should used (default=\PHP_INT_MAX)
       * - <b>AllowUrls</b>         : Can the text contain URLs to be valid? (default=TRUE)
       * - <b>MaxUrlCount</b>       : The max. count of allowed unknown URLs inside the text to validate.
       *                              The default value -1 means, no limit.
       * - <b>HostWhiteList</b>     : Defining Host names, allowed to be used uncounted in URLs and mailaddresses. array
       * - <b>AllowMailAddresses</b>: Can the text contain mail adresses to be valid? (default=TRUE)
       * - <b>CheckForSpam</b>      : Should the text be checked if it contains some spam? (default=FALSE)
       *                              It checks for some buzzwords and also checks for some spam hidding spellings
       *                              like: V-I-A-G-R-A or something else.
       * - <b>AllowNewLines</b>     : Can the text contain some linebreaks to be valid (default=TRUE)
       * - <b>MaxLineCount</b>      : How many lines can be defined by the value to check, to be valid?
       *                              (Default = -1 means no limit and 0 is equal to 1 because 0 lines have no sense)
       * - <b>AllowHtml</b>         : Can the value to check contains some HTML content? (default=TRUE)
       * - <b>HtmlConverter</b>     : If HTML is allowed here you can define the Converter {@see \BF\Converter\IHtmlToX}
       *
       * @param  array   $options  All validator options
       */
      public function __construct( array $options = array() )
      {

         // Setting the default option values, if they are currently not defined
         self::setIntegerOption( 'MinLength',          $options,   1,              true );
         self::setIntegerOption( 'MaxLength',          $options,   \PHP_INT_MAX,   true );
         self::setIntegerOption( 'MaxUrlCount',        $options,   -1 );
         self::setBooleanOption( 'AllowUrls',          $options,   true );
         self::setBooleanOption( 'AllowMailAddresses', $options,   true );
         self::setBooleanOption( 'CheckForSpam',       $options,   false );
         self::setArrayOption  ( 'HostWhiteList',      $options );
         self::setBooleanOption( 'AllowNewLines',      $options,   true );
         self::setBooleanOption( 'AllowHtml',          $options,   true );
         self::setIntegerOption( 'MaxLineCount',       $options,   -1 );
         self::setBooleanOption( 'HtmlConverter',      $options,   null,           true );
         $options[ 'Result' ] = '';

         // Calling the parent contructor
         parent::__construct( $options );

      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P U B L I C   M E T H O D S   - - - - - - - - - - - - - - - - - - - - - -">

      /**
       * Sets a option value.
       *
       * @param string $optionName The name of the option to set the value at.
       * @param mixed  $value      The new value. (the value type depends to the option)
       */
      public function setOption( $optionName, $value )
      {

         $resultValue = null;

         switch ( $optionName )
         {

            case 'MinLength':
            case 'MaxLength':
               if ( \BF\TypeTool::IsInteger( $value ) )
               {
                  $this->_options[ $optionName ] = \intval( $value );
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = null;
               }
               $this->LastResult = null;
               break;

            case 'MaxUrlCount':
               if ( \BF\TypeTool::IsInteger( $value ) )
               {
                  $value = \intval( $value );
                  if ( $value < -1 ) { $value = -1; }
                  $this->_options[ $optionName ] = $value;
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = -1;
               }
               $this->LastResult = null;
               break;

            case 'MaxLineCount':
               if ( \BF\TypeTool::IsInteger( $value ) )
               {
                  $value = \intval( $value );
                  if ( $value < 1 ) { $value = -1; }
                  $this->_options[ $optionName ] = $value;
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = -1;
               }
               $this->LastResult = null;
               break;

            case 'AllowUrls':
            case 'AllowMailAddresses':
            case 'AllowNewLines':
            case 'AllowHtml':
               if ( \BF\TypeTool::IsBoolConvertible( $value, $resultValue ) )
               {
                  $this->_options[ $optionName ] = $resultValue;
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = true;
               }
               $this->LastResult = null;
               break;

            case 'CheckForSpam':
               if ( \BF\TypeTool::IsBoolConvertible( $value, $resultValue ) )
               {
                  $this->_options[ $optionName ] = $resultValue;
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = false;
               }
               $this->LastResult = null;
               break;

            case 'HostWhiteList':
               if ( \is_array( $value ) )
               {
                  $this->_options[ $optionName ] = $value;
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = array();
               }
               $this->LastResult = null;
               break;

            case 'HtmlConverter':
               if ( ( $value instanceof \BF\Converter\IHtmlToX ) )
               {
                  $this->_options[ $optionName ] = $value;
               }
               elseif ( \is_null( $value ) )
               {
                  $this->_options[ $optionName ] = null;
               }
               $this->LastResult = null;
               break;

            default:
               parent::setOption( $optionName, $value );
               break;

         }

      }

      # </editor-fold>

      # <editor-fold defaultstate="collapsed" desc=" - - -   P R O T E C T E D   M E T H O D S   - - - - - - - - - - - - - - - - - - -">

      protected function __validate()
      {

         $this->_message = '';

         $resultString = null;

         if ( ! \BF\TypeTool::IsStringConvertible( $this->_value, $resultString ) )
         {

            $this->_message = \BF\_1(
               '_Validation',
               'This is not a valid %s!',
               \BF\_0( '_Validation', 'string value' )
            );

            return $this->__setLastResult( false );

         }

         $this->_options[ 'Result' ] = $resultString;

         if ( isset( $this->_options[ 'MinLength' ] )
           && \BF\strlen( $this->_options[ 'Result' ]) < $this->_options[ 'MinLength' ] )
         {

            $this->_message = \BF\_1(
               '_Validation',
               'The value is shorter than allowed! (Allowed minimal length is %d)',
               $this->_options[ 'MinLength' ]
            );

            return $this->__setLastResult( false );

         }



         if ( isset( $this->_options[ 'MaxLength' ] )
           && \BF\strlen( $this->_options[ 'Result' ] ) > $this->_options[ 'MaxLength' ] )
         {

            $this->_message = \BF\_2(
               '_Validation',
               'The %s value is longer than allowed! (Allowed maximal length is %d)',
               $this->_options[ 'DisplayName' ],
               $this->_options[ 'MaxLength' ]
            );

            return $this->__setLastResult( false );

         }

         if ( ! $this->_options[ 'AllowNewLines' ] || $this->_options[ 'MaxLineCount' ] > 0 )
         {
            $lines = \BF\splitLines( $this->_options[ 'Result' ] );
            $lineCount = \count( $lines );
            if ( ! $this->_options[ 'AllowNewLines' ] && $lineCount > 1 )
            {
               $this->_message = \BF\_1(
                  '_Validation',
                  'The %s value contains line breaks. (This is not allowed!)',
                  $this->_options[ 'DisplayName' ]
               );
               return $this->__setLastResult( false );
            }
            if ( $this->_options[ 'MaxLineCount' ] > 0 && $lineCount > $this->_options[ 'MaxLineCount' ] )
            {
               $this->_message = \BF\_3(
                  '_Validation',
                  'The %s value contains %d line breaks. (Allowed are max. %d!)',
                  $this->_options[ 'DisplayName' ],
                  $lineCount,
                  $this->_options[ 'MaxLineCount' ]
               );
               return $this->__setLastResult( false );
            }
         }

         $diff = \strip_tags( $this->_options[ 'Result' ] );

         if ( $this->_options[ 'Result' ] !== $diff )
         {
            if ( ! $this->_options[ 'AllowHtml' ] )
            {
               $this->_message = \BF\_1(
                  '_Validation',
                  'The %s value contains HTML markup. (This is not allowed!)',
                  $this->_options[ 'DisplayName' ]
               );
               return $this->__setLastResult( false );
            }
            if ( isset( $this->_options[ 'HtmlConverter' ] )
              && ( $this->_options[ 'HtmlConverter' ] instanceof \BF\Converter\IHtmlToX ) )
            {
               $this->_options[ 'HtmlConverter' ]->setHTML( $this->_options[ 'Result' ] );
               $this->_options[ 'Result' ] = $this->_options[ 'HtmlConverter' ]->getResult();
            }
         }

         if ( ! $this->_options[ 'AllowUrls' ] || $this->_options[ 'MaxUrlCount' ] > -1 )
         {
            // Check for urls inside the value (text)
            $urls = \BF\Net\Url::FindAllUrls( $this->_options[ 'Result' ], $this->_options[ 'HostWhiteList' ] );

            if ( ( ! $this->_options[ 'AllowUrls' ] && \count( $urls ) > 0 )
              || ( $this->_options[ 'MaxUrlCount' ] > -1 && \count( $urls ) > $this->_options[ 'MaxUrlCount' ] ) )
            {
               if ( $this->_options[ 'MaxUrlCount' ] < 1 )
               {
                  $this->_message = \BF\_1(
                     '_Validation',
                     'The %s value contains some URLs. This is not allowed!',
                     $this->_options[ 'DisplayName' ]
                  );
               }
               else
               {
                  $this->_message = \BF\_2(
                     '_Validation',
                     'The %s value contains more than %d URLs (web addresses)!',
                     $this->_options[ 'DisplayName' ],
                     $this->_options[ 'MaxUrlCount' ]
                  );
               }

               return $this->__setLastResult( false );
            }
         }

         $mailadresses = \BF\Net\MailAddress::ExctractAllFromString( $this->_options[ 'Result' ] );

         if ( ! $this->_options[ 'AllowMailAddresses' ] && \count( $mailadresses ) > 0 )
         {

            $this->_message = \BF\_1(
               '_Validation',
               'The %s value contains some mail addresses. This is not allowed!',
               $this->_options[ 'DisplayName' ]
            );

            return $this->__setLastResult( false );

         }

         if ( $this->_options[ 'CheckForSpam' ] )
         {

            if ( \preg_match( \BF\RX::BADWORDS, $this->_options[ 'Result' ] ) )
            {
               $this->_message = \BF\_1(
                  '_Validation',
                  'The %s value contains content (words) that says it is spam.',
                  $this->_options[ 'DisplayName' ]
               );
               return $this->__setLastResult( false );
            }

            if ( ! $this->_options[ 'AllowHtml' ] && \preg_match( \BF\RX::HTML_ENTITY, $this->_options[ 'Result' ] ) )
            {
               $this->_message = \BF\_1(
                  '_Validation',
                  'The %s value contains content (entities) that can be spam.',
                  $this->_options[ 'DisplayName' ]
               );
               return $this->__setLastResult( false );
            }

            if ( \preg_match( \BF\RX::INCONSISTENT_TEXT, $this->_options[ 'Result' ] ) )
            {
               $this->_message = \BF\_1(
                  '_Validation',
                  'The %s value contains content that looks like spam.',
                  $this->_options[ 'DisplayName' ]
               );
               return $this->__setLastResult( false );
            }

            if ( \preg_match( \BF\RX::URL_ENCODING, $this->_options[ 'Result' ] ) )
            {
               $this->_message = \BF\_1(
                  '_Validation',
                  'The %s value contains encoded content that can be spam.',
                  $this->_options[ 'DisplayName' ]
               );
               return $this->__setLastResult( false );
            }

         }

         return $this->__setLastResult( true );

      }

      # </editor-fold>

   }

}


